package besta.moon.engine.selector.multioper;

import besta.moon.engine.Index;
import besta.moon.engine.RowSource;
import besta.moon.sql.expression.Expressions;

public final class Distinct extends RowSource {

    final private Expressions distinctColumns;
    final private RowSource rowSource;
    private Index index;
    private int row;

    public Distinct(RowSource rowSource, Expressions columns) {
        this.rowSource = rowSource;
        this.distinctColumns = columns;
    }

    @Override
    public final void execute() throws Exception {
        rowSource.execute();
        index = new Index(true);
    }

    @Override
    public final boolean isScrollable() {
        return false;
    }

    @Override
    public final void beforeFirst() throws Exception {
        rowSource.beforeFirst();
        row = 0;
    }

    @Override
    public final boolean first() throws Exception {
        beforeFirst();
        return next();
    }

    @Override
    public final boolean next() throws Exception {
        while (true) {
            boolean isNext = rowSource.next();
            if (!isNext) {
                return false;
            }

            Long oldRowOffset = (Long) index.findRows(distinctColumns, true, null);
            long newRowOffset = rowSource.getRowPosition();
            if (oldRowOffset == null) {
                index.addValues(newRowOffset, distinctColumns);
                row++;
                return true;
            } else if (oldRowOffset == newRowOffset) {
                row++;
                return true;
            }
        }
    }

    @Override
    public final void afterLast() throws Exception {
        rowSource.afterLast();
        row = 0;
    }

    @Override
    public final int getRow() throws Exception {
        return row;
    }

    @Override
    public final long getRowPosition() {
        return rowSource.getRowPosition();
    }

    @Override
    public final void setRowPosition(long rowPosition) throws Exception {
        rowSource.setRowPosition(rowPosition);
    }

    @Override
    public final void nullRow() {
        rowSource.nullRow();
        row = 0;
    }

    @Override
    public final void noRow() {
        rowSource.noRow();
        row = 0;
    }

    @Override
    public final boolean rowInserted() {
        return rowSource.rowInserted();
    }

    @Override
    public final boolean rowDeleted() {
        return rowSource.rowDeleted();
    }

    @Override
    public boolean isExpressionsFromThisRowSource(Expressions columns) {
        return rowSource.isExpressionsFromThisRowSource(columns);
    }
}
